#include "ledgfx.h"
//#include "Adafruit_GFX.h"
#include "twimaster.h"
#include <avr/io.h>
#include <stdlib.h>

uint32_t eemuster_folge[len_folge] EEMEM = {14680078,15139278,473536,15139278,14680078,28311579,28869179,18383409,575008,913248,473536,913248,575008,17408,10240,4096,328000,17825809,18153809,18157905,22369621,29201275,33412991,15587182,15583086,15255086,33080895,11512810,4357252,11512810,33080895,28869179,18383409,17825809,18153809,29197179,13103046,7302636,29197179,28311579};
uint32_t eemuster_folge_2[len_folge_2] EEMEM = {14680078,15139278,473536,15139278,14680078,28311579,885600,27648,885600,28311579,28312416,28339200,29196288,912384,28512,891,27675,884763,28311579,17825809,18153809,18157905,332096,4096,145536,4357252,4685252,22511061,33554431,33550335,33550207,33549951,33541759,33279615,33148543,33083007,33080959,33080895,33080893,33080889,33080881,33080865,33080353,33063969,32539681,3115074,4357252,8659944,17318431,17318671,17326471,17576131,26097891,13331878,6407948,3179032,7340060,14680078,29360135,25690147,20988933,18907657,17825809,2621480,4211716,8421890,17825809,26247699,2949480,4353156,8749890,328000,469440,469326,15018318,15022414,33095231,32537631,14694414,14684174};
uint32_t eemuster_folge_fade[len_folge_fade] EEMEM = {14680078,459200,14336,688800,22020117,10507274,22030357,710304,10824010,22730421,10824010,22041621,11512810,4211716,8421890,17825809,2621480,4211716,8421890,17825809,2621480,12633606,26247699,2949480,4353156,8749890,20447289,12961606,28869179,7161196,17971345,4539716,141440,332096,2762920,4543812,11184810,22369621,10496010,459200};
uint32_t eemuster_bonvoyage[len_bonvoyage] EEMEM = {32641183,16405135,33182344,33182344,25304216,0,33216174,589344,33182409,17333776,32641183,33080878,16405135,25304216,0,33216174,15255086,32772191,25363672,15255086,25304216,16405135,15259319,33216181,29696,0};
uint32_t eemuster_orakel_start[len_orakel_start] EEMEM = {15255086,33182409,16405135,32649793,33216181,32539681,0,0};
uint32_t eemuster_orakel[len_orakel] EEMEM = {13182540,13582284,1030272,1016800,3276036,4488452,4291652,4674692,4347332,8380391,26189816,2132104,20287859,15716206,546560,29696,1055775,15430465,25361580,53230,16481999,2588098,2393378,1044868};
uint32_t eemuster_arrows[len_arrows] EEMEM = {4488452,1659678,4347332,17077359,4291652,15832368,4674692,32264769};

uint8_t red[5][5];
uint8_t green[5][5];
uint8_t blue[5][5];
/*
uint8_t getred(int8_t x,int8_t x,){
	return red[x][y];
}
uint8_t getgreen(int8_t x,int8_t x,){
	return green[x][y];
}
uint8_t getblue(int8_t x,int8_t x,){
	return blue[x][y];
}
*/
uint32_t getPixel(int8_t x,int8_t y){
	//touch_status |= ((uint32_t) 1 << 31);
	uint32_t pixelcolour=((uint32_t)(red[x][y])<<16);
	//transmitByte(red[x][y]);
	pixelcolour|=((uint32_t)(green[x][y])<<8);
	pixelcolour|=((uint32_t)(blue[x][y]));
	//transmitByte(pixelcolour);
	return pixelcolour;
}
void drawPixel(int8_t x, int8_t y, uint8_t c_red, uint8_t c_green, uint8_t c_blue) {
  if ((y < 0) || (y >= 5)) return;
  if ((x < 0) || (x >= 5)) return;

 // check rotation, move pixel around if necessary
  switch (getRotation()) {
  case 1:
    swap(x, y);
    x = 5 - x - 1;
    break;
  case 2:
    x = 5 - x - 1;
    y = 5 - y - 1;
    break;
  case 3:
    swap(x, y);
    y = 5 - y - 1;
    break;
  }

  // wrap around the x
  //x += 4; // was ist das?
  //x %= 5;
if (c_red<60) red[x][y]=c_red;
	else red[x][y]=0;

if (c_green<60) green[x][y]=c_green;
else green[x][y]=0;

if (c_blue<60) blue[x][y]=c_blue;
else blue[x][y]=0;



  
}

void drawLine(int8_t x0, int8_t y0, int8_t x1, int8_t y1, uint8_t c_red, uint8_t c_green, uint8_t c_blue) {
	int8_t steep = abs(y1 - y0) > abs(x1 - x0);
	if (steep) {
		swap(x0, y0);
		swap(x1, y1);
	}

	if (x0 > x1) {
		swap(x0, x1);
		swap(y0, y1);
	}

	int8_t dx, dy;
	dx = x1 - x0;
	dy = abs(y1 - y0);

	int8_t err = dx / 2;
	int8_t ystep;

	if (y0 < y1) {
		ystep = 1;
	} else {
		ystep = -1;
	}

	for (; x0<=x1; x0++) {
		if (steep) {
			 drawPixel(y0, x0, c_red, c_green, c_blue);
		} else {
			 drawPixel(x0, y0, c_red, c_green, c_blue);
		}
		err -= dy;
		if (err < 0) {
			y0 += ystep;
			err += dx;
		}
	}
}


void led_out() {
	
	i2c_start_wait(0x50+I2C_WRITE); 	// set device address and write mode
	i2c_write(0x00);         		    // write command
	
	for (uint8_t ct_line=0;ct_line<5;ct_line++){
		for (uint8_t ct_collum=0;ct_collum<5;ct_collum++){
			if ((ct_line==1)&&(ct_collum==4))		//after 8 rgb leds change to next atmega
			{	//return;
				i2c_write(red[2][4]);
				i2c_write(blue[1][3]);
				i2c_stop();                     	// set stop conditon = release bus
				i2c_start_wait(0x52+I2C_WRITE); 	// set device address and write mode
				i2c_write(0x00);         		    // write command
			}
			if ((ct_line==3)&&(ct_collum==2))		//after 16 rgb leds change to next atmega
			{	//i2c_write(red[2][4]);
				i2c_stop();                     	// set stop conditon = release bus
				i2c_start_wait(0x54+I2C_WRITE); 	// set device address and write mode
				i2c_write(0x00);         		    // write command
			}
			i2c_write(red[ct_line][ct_collum]);                	// write data
			i2c_write(green[ct_line][ct_collum]);                	// write data
			i2c_write(blue[ct_line][ct_collum]);                	// write data
		}
	}
	//i2c_write(red[2][4]); 
	i2c_stop();
}

// draw a circle outline
void drawCircle(int16_t x0, int16_t y0, int16_t r, 
			      uint8_t c_red, uint8_t c_green, uint8_t c_blue) {
  int16_t f = 1 - r;
  int16_t ddF_x = 1;
  int16_t ddF_y = -2 * r;
  int16_t x = 0;
  int16_t y = r;

  drawPixel(x0, y0+r, c_red, c_green, c_blue);
  drawPixel(x0, y0-r, c_red, c_green, c_blue);
  drawPixel(x0+r, y0, c_red, c_green, c_blue);
  drawPixel(x0-r, y0, c_red, c_green, c_blue);

  while (x<y) {
    if (f >= 0) {
      y--;
      ddF_y += 2;
      f += ddF_y;
    }
    x++;
    ddF_x += 2;
    f += ddF_x;
  
    drawPixel(x0 + x, y0 + y, c_red, c_green, c_blue);
    drawPixel(x0 - x, y0 + y, c_red, c_green, c_blue);
    drawPixel(x0 + x, y0 - y, c_red, c_green, c_blue);
    drawPixel(x0 - x, y0 - y, c_red, c_green, c_blue);
    drawPixel(x0 + y, y0 + x, c_red, c_green, c_blue);
    drawPixel(x0 - y, y0 + x, c_red, c_green, c_blue);
    drawPixel(x0 + y, y0 - x, c_red, c_green, c_blue);
    drawPixel(x0 - y, y0 - x, c_red, c_green, c_blue);
    
  }
}
/*
void drawCircleHelper( int16_t x0, int16_t y0,
               int16_t r, uint8_t cornername, uint8_t c_red, uint8_t c_green, uint8_t c_blue) {
  int16_t f     = 1 - r;
  int16_t ddF_x = 1;
  int16_t ddF_y = -2 * r;
  int16_t x     = 0;
  int16_t y     = r;

  while (x<y) {
    if (f >= 0) {
      y--;
      ddF_y += 2;
      f     += ddF_y;
    }
    x++;
    ddF_x += 2;
    f     += ddF_x;
    if (cornername & 0x4) {
      drawPixel(x0 + x, y0 + y, c_red, c_green, c_blue);
      drawPixel(x0 + y, y0 + x, c_red, c_green, c_blue);
    } 
    if (cornername & 0x2) {
      drawPixel(x0 + x, y0 - y, c_red, c_green, c_blue);
      drawPixel(x0 + y, y0 - x, c_red, c_green, c_blue);
    }
    if (cornername & 0x8) {
      drawPixel(x0 - y, y0 + x, c_red, c_green, c_blue);
      drawPixel(x0 - x, y0 + y, c_red, c_green, c_blue);
    }
    if (cornername & 0x1) {
      drawPixel(x0 - y, y0 - x, c_red, c_green, c_blue);
      drawPixel(x0 - x, y0 - y, c_red, c_green, c_blue);
    }
  }
}
*/
void fillCircle(int16_t x0, int16_t y0, int16_t r, 
			      uint8_t c_red, uint8_t c_green, uint8_t c_blue) {
  drawFastVLine(x0, y0-r, 2*r+1, c_red, c_green, c_blue);
  fillCircleHelper(x0, y0, r, 3, 0, c_red, c_green, c_blue);
}

// used to do circles and roundrects!
void fillCircleHelper(int16_t x0, int16_t y0, int16_t r,
				    uint8_t cornername, int16_t delta, uint8_t c_red, uint8_t c_green, uint8_t c_blue) {

  int16_t f     = 1 - r;
  int16_t ddF_x = 1;
  int16_t ddF_y = -2 * r;
  int16_t x     = 0;
  int16_t y     = r;

  while (x<y) {
    if (f >= 0) {
      y--;
      ddF_y += 2;
      f     += ddF_y;
    }
    x++;
    ddF_x += 2;
    f     += ddF_x;

    if (cornername & 0x1) {
      drawFastVLine(x0+x, y0-y, 2*y+1+delta, c_red, c_green, c_blue);
      drawFastVLine(x0+y, y0-x, 2*x+1+delta, c_red, c_green, c_blue);
    }
    if (cornername & 0x2) {
      drawFastVLine(x0-x, y0-y, 2*y+1+delta, c_red, c_green, c_blue);
      drawFastVLine(x0-y, y0-x, 2*x+1+delta, c_red, c_green, c_blue);
    }
  }
}

// bresenham's algorithm - thx wikpedia


// draw a rectangle
void drawRect(int16_t x, int16_t y, 
			    int16_t w, int16_t h, 
			    uint8_t c_red, uint8_t c_green, uint8_t c_blue) {
  drawFastHLine(x, y, w, c_red, c_green, c_blue);
  drawFastHLine(x, y+h-1, w, c_red, c_green, c_blue);
  drawFastVLine(x, y, h, c_red, c_green, c_blue);
  drawFastVLine(x+w-1, y, h, c_red, c_green, c_blue);
}

void drawFastVLine(int16_t x, int16_t y, 
				 int16_t h, uint8_t c_red, uint8_t c_green, uint8_t c_blue) {
  // stupidest version - update in subclasses if desired!
  drawLine(x, y, x, y+h-1, c_red, c_green, c_blue);
}


void drawFastHLine(int16_t x, int16_t y, 
				 int16_t w, uint8_t c_red, uint8_t c_green, uint8_t c_blue) {
  // stupidest version - update in subclasses if desired!
  drawLine(x, y, x+w-1, y, c_red, c_green, c_blue);
}

void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, 
			    uint8_t c_red, uint8_t c_green, uint8_t c_blue) {
  // stupidest version - update in subclasses if desired!
  for (int16_t i=x; i<x+w; i++) {
    drawFastVLine(i, y, h, c_red, c_green, c_blue); 
  }
}


void fillScreen(uint8_t c_red, uint8_t c_green, uint8_t c_blue) {
  fillRect(0, 0, _width, _height, c_red, c_green, c_blue);
}
/*
// draw a rounded rectangle!
void drawRoundRect(int16_t x, int16_t y, int16_t w,
  int16_t h, int16_t r, uint8_t c_red, uint8_t c_green, uint8_t c_blue) {
  // smarter version
  drawFastHLine(x+r  , y    , w-2*r, c_red, c_green, c_blue); // Top
  drawFastHLine(x+r  , y+h-1, w-2*r, c_red, c_green, c_blue); // Bottom
  drawFastVLine(  x    , y+r  , h-2*r, c_red, c_green, c_blue); // Left
  drawFastVLine(  x+w-1, y+r  , h-2*r, c_red, c_green, c_blue); // Right
  // draw four corners
  drawCircleHelper(x+r    , y+r    , r, 1, c_red, c_green, c_blue);
  drawCircleHelper(x+w-r-1, y+r    , r, 2, c_red, c_green, c_blue);
  drawCircleHelper(x+w-r-1, y+h-r-1, r, 4, c_red, c_green, c_blue);
  drawCircleHelper(x+r    , y+h-r-1, r, 8, c_red, c_green, c_blue);
}
*/
/*
// fill a rounded rectangle!
void fillRoundRect(int16_t x, int16_t y, int16_t w,
				 int16_t h, int16_t r, uint8_t c_red, uint8_t c_green, uint8_t c_blue) {
  // smarter version
  fillRect(x+r, y, w-2*r, h, c_red, c_green, c_blue);

  // draw four corners
  fillCircleHelper(x+w-r-1, y+r, r, 1, h-2*r-1, c_red, c_green, c_blue);
  fillCircleHelper(x+r    , y+r, r, 2, h-2*r-1, c_red, c_green, c_blue);
}
*/
/*
// draw a triangle!
void drawTriangle(int16_t x0, int16_t y0,
				int16_t x1, int16_t y1, 
				int16_t x2, int16_t y2, uint8_t c_red, uint8_t c_green, uint8_t c_blue) {
  drawLine(x0, y0, x1, y1, c_red, c_green, c_blue);
  drawLine(x1, y1, x2, y2, c_red, c_green, c_blue);
  drawLine(x2, y2, x0, y0, c_red, c_green, c_blue);
}

// fill a triangle!
void fillTriangle ( int16_t x0, int16_t y0,
				  int16_t x1, int16_t y1, 
				  int16_t x2, int16_t y2, uint8_t c_red, uint8_t c_green, uint8_t c_blue) {

  int16_t a, b, y, last;

  // Sort coordinates by Y order (y2 >= y1 >= y0)
  if (y0 > y1) {
    swap(y0, y1); swap(x0, x1);
  }
  if (y1 > y2) {
    swap(y2, y1); swap(x2, x1);
  }
  if (y0 > y1) {
    swap(y0, y1); swap(x0, x1);
  }

  if(y0 == y2) { // Handle awkward all-on-same-line case as its own thing
    a = b = x0;
    if(x1 < a)      a = x1;
    else if(x1 > b) b = x1;
    if(x2 < a)      a = x2;
    else if(x2 > b) b = x2;
    drawFastHLine(a, y0, b-a+1, c_red, c_green, c_blue);
    return;
  }

  int16_t
    dx01 = x1 - x0,
    dy01 = y1 - y0,
    dx02 = x2 - x0,
    dy02 = y2 - y0,
    dx12 = x2 - x1,
    dy12 = y2 - y1,
    sa   = 0,
    sb   = 0;

  // For upper part of triangle, find scanline crossings for segments
  // 0-1 and 0-2.  If y1=y2 (flat-bottomed triangle), the scanline y1
  // is included here (and second loop will be skipped, avoiding a /0
  // error there), otherwise scanline y1 is skipped here and handled
  // in the second loop...which also avoids a /0 error here if y0=y1
  // (flat-topped triangle).
  if(y1 == y2) last = y1;   // Include y1 scanline
  else         last = y1-1; // Skip it

  for(y=y0; y<=last; y++) {
    a   = x0 + sa / dy01;
    b   = x0 + sb / dy02;
    sa += dx01;
    sb += dx02;
    //longhand:
    //a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
    //b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
    
    if(a > b) swap(a,b);
    drawFastHLine(a, y, b-a+1, c_red, c_green, c_blue);
  }

  // For lower part of triangle, find scanline crossings for segments
  // 0-2 and 1-2.  This loop is skipped if y1=y2.
  sa = dx12 * (y - y1);
  sb = dx02 * (y - y0);
  for(; y<=y2; y++) {
    a   = x1 + sa / dy12;
    b   = x0 + sb / dy02;
    sa += dx12;
    sb += dx02;
    // longhand:
    //a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
    //b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
    
    if(a > b) swap(a,b);
    drawFastHLine(a, y, b-a+1, c_red, c_green, c_blue);
  }
}
*/
/*
void drawBitmap(int16_t x, int16_t y, 
			      const uint8_t *bitmap, int16_t w, int16_t h,
			      uint8_t c_red, uint8_t c_green, uint8_t c_blue) {

  int16_t i, j, byteWidth = (w + 7) / 8;

  for(j=0; j<h; j++) {
    for(i=0; i<w; i++ ) {
      if(pgm_read_byte(bitmap + j * byteWidth + i / 8) & (128 >> (i & 7))) {
	drawPixel(x+i, y+j, c_red, c_green, c_blue);
      }
    }
  }
}
*/
/*
#if ARDUINO >= 100
size_t write(uint8_t c) {
#else
void write(uint8_t c) {
#endif
  if (c == '\n') {
    cursor_y += textsize*8;
    cursor_x = 0;
  } else if (c == '\r') {
    // skip em
  } else {
    drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize);
    cursor_x += textsize*6;
    if (wrap && (cursor_x > (_width - textsize*6))) {
      cursor_y += textsize*8;
      cursor_x = 0;
    }
  }
#if ARDUINO >= 100
  return 1;
#endif
}
*/

// draw a character
void drawChar(int8_t x_offset, uint32_t letter, uint8_t c_red, uint8_t c_green, uint8_t c_blue)
{
	
	uint32_t ct_led=1;
	
	//transmitByte(c);

	for(uint8_t x=0;x<5;x++)
	{
		for(uint8_t y=0;y<5;y++)
		{
			if ((letter&ct_led)){
				drawPixel(x + x_offset, y, c_red, c_green, c_blue);
			}
			ct_led=ct_led<<1;
		}
	}
}   
uint8_t getRotation(void) {
  rotation %= 4;
  return rotation;
}


void setRotation(uint8_t x) {
  x %= 4;  // cant be higher than 3
  rotation = x;
  /*switch (x) {
  case 0:
  case 2:
    _width = WIDTH;
    _height = HEIGHT;
    break;
  case 1:
  case 3:
    _width = HEIGHT;
    _height = WIDTH;
    break;
	
  }*/
}


void invertDisplay() {
  for (uint8_t x=0;x<5;x++)
  {
	  for (uint8_t y=0;y<5;y++)
	  {
  
   
		  red[x][y]=59-red[x][y];
		  green[x][y]=59-green[x][y];
		  blue[x][y]=59-blue[x][y];
	  }
  }			
}

/*
// return the size of the display which depends on the rotation!
int16_t width(void) { 
  return _width; 
}
 
int16_t height(void) { 
  return _height; 
}
*/